#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
滇西科技师范学院课程表展示Web应用
使用Flask框架展示各班级课程表
"""

from flask import Flask, render_template, request, jsonify
import json
import os
import re
import threading
import logging
from pure_scraper import set_cookies, scrape_classes, scrape_teachers
from config import config
from models import db, ClassSchedule, TeacherSchedule, ScheduleManager

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def create_app():
    """创建Flask应用"""
    app = Flask(__name__)

    # 加载配置
    config_name = os.environ.get('FLASK_ENV', 'development')
    app.config.from_object(config[config_name])

    # 初始化数据库
    db.init_app(app)

    return app

app = create_app()

class ScheduleParser:
    """课程表解析器"""
    
    def __init__(self):
        # 课程时间配置
        self.time_slots = {
            1: "8:00-8:45",
            2: "8:55-9:40", 
            3: "9:55-10:40",
            4: "10:55-11:40",
            5: "11:50-12:35",
            6: "14:00-14:45",
            7: "14:55-15:40",
            8: "15:55-16:40",
            9: "16:55-17:40",
            10: "17:50-18:35",
            11: "19:30-20:15",
            12: "20:25-21:10",
            13: "21:20-22:05"
        }
        
        # 星期映射
        self.weekdays = {
            '1': '星期一',
            '2': '星期二', 
            '3': '星期三',
            '4': '星期四',
            '5': '星期五',
            '6': '星期六',
            '7': '星期日'
        }
    
    def parse_schedule_data(self, schedule_data):
        """解析课程表数据"""
        if not schedule_data or 'schedules' not in schedule_data:
            return []
        
        parsed_courses = []
        
        for course in schedule_data['schedules']:
            # 根据数据结构判断是班级课表还是教师课表
            if 'JSM' in course:  # 教师课表字段
                course_name = course.get('KCM', '')
                teacher = course.get('JSM', '')  # 教师课表使用JSM字段
                location = course.get('JASMC', '')  # 教室
                weekday = course.get('SKXQ', '')  # 星期几
                start_period = course.get('KSJC', '')  # 开始节次
                end_period = course.get('JSJC', '')  # 结束节次
                week_range = course.get('ZCMC', '')  # 周次范围
                class_name = course.get('SKBJ', '')  # 教师课表使用SKBJ字段
            else:  # 班级课表字段
                course_name = course.get('KCM', '')
                teacher = course.get('SKJS', '')
                location = course.get('JASMC', '')
                weekday = course.get('SKXQ', '')
                start_period = course.get('KSJC', '')
                end_period = course.get('JSJC', '')
                week_range = course.get('ZCMC', '')
                class_name = course.get('BJMC', '')
            
            # 验证必要字段
            if not all([course_name, teacher, location, weekday, start_period, end_period]):
                continue
            
            # 转换星期
            try:
                weekday_num = int(weekday)
            except (ValueError, TypeError):
                continue
            
            # 转换节次
            try:
                start_period_num = int(start_period)
                end_period_num = int(end_period)
            except (ValueError, TypeError):
                continue
            
            # 解析周次范围
            week_info = self._parse_week_range(week_range)
            
            parsed_courses.append({
                'course_name': course_name,
                'teacher': teacher,
                'location': location,
                'weekday': weekday_num,
                'start_period': start_period_num,
                'end_period': end_period_num,
                'week_range': week_info,
                'class_name': class_name,
                'course_code': course.get('KCH', ''),
                'is_experiment': course.get('ISTK', 0) == 1,  # 是否为实验课
                'total_weeks': week_range,
                'teaching_unit': course.get('KKDWDM', ''),
                'class_size': course.get('XKZRS', 0)
            })
        
        return parsed_courses
    
    def _convert_weekday(self, weekday):
        """转换星期文字为数字"""
        weekday_map = {
            '一': 1, '二': 2, '三': 3, '四': 4, 
            '五': 5, '六': 6, '日': 7
        }
        return weekday_map.get(weekday)
    
    def _parse_week_range(self, week_range):
        """解析周次范围"""
        # 处理格式如：1-16周, 1-15周(单), 12-15周
        week_match = re.match(r'(\d+)-(\d+)周(?:\(([^)]+)\))?', week_range)
        if week_match:
            start_week = int(week_match.group(1))
            end_week = int(week_match.group(2))
            week_type = week_match.group(3) if week_match.group(3) else None
            return {
                'start': start_week,
                'end': end_week,
                'type': week_type,
                'range_text': week_range
            }
        return None
    
    def generate_schedule_table(self, courses):
        """生成课程表表格数据"""
        # 创建7x13的表格（7天x13节课）
        schedule_table = [[None for _ in range(13)] for _ in range(7)]
        
        for course in courses:
            weekday = course['weekday'] - 1  # 转换为0-6索引
            start_period = course['start_period'] - 1  # 转换为0-12索引
            end_period = course['end_period'] - 1
            
            # 检查时间范围是否有效
            if not (0 <= weekday <= 6 and 0 <= start_period <= 12 and 0 <= end_period <= 12):
                continue
            
            # 填充课程信息到对应的时间段
            for period in range(start_period, end_period + 1):
                if period < 13:  # 确保不超出范围
                    schedule_table[weekday][period] = course
        
        return schedule_table

parser = ScheduleParser()

# 采集状态管理
scraping_status = {
    'class_scraping': False,
    'teacher_scraping': False,
    'class_progress': 0,
    'teacher_progress': 0,
    'class_message': '',
    'teacher_message': ''
}

def get_database_stats():
    """获取数据库统计信息"""
    try:
        with app.app_context():
            classes_count = len(ScheduleManager.get_class_list())
            teachers_count = len(ScheduleManager.get_teacher_list())
            class_schedules_count = ClassSchedule.query.count()
            teacher_schedules_count = TeacherSchedule.query.count()

            return {
                'classes_count': classes_count,
                'teachers_count': teachers_count,
                'class_schedules_count': class_schedules_count,
                'teacher_schedules_count': teacher_schedules_count
            }
    except Exception as e:
        logger.error(f"获取数据库统计失败: {e}")
        return {
            'classes_count': 0,
            'teachers_count': 0,
            'class_schedules_count': 0,
            'teacher_schedules_count': 0
        }

@app.route('/')
def index():
    """首页"""
    try:
        stats = get_database_stats()
        return render_template('index_new.html', **stats)
    except Exception as e:
        logger.error(f"首页加载失败: {e}")
        return render_template('index_new.html', error=f"数据加载失败: {e}")



@app.route('/scrape')
def scrape_control():
    """数据采集控制页面"""
    return render_template('scrape_control.html')



@app.route('/api/classes')
def api_classes():
    """获取班级列表API（支持条件查询和分页）"""
    try:
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 20, type=int)  # 每页默认20条
        search = request.args.get('search', '', type=str)  # 搜索关键词
        year = request.args.get('year', '', type=str)  # 年级筛选
        semester = request.args.get('semester', '', type=str)  # 学期筛选
        college = request.args.get('college', '', type=str)  # 学院筛选

        # 限制每页最大数量
        per_page = min(per_page, 100)

        with app.app_context():
            result = ScheduleManager.get_class_list_paginated(
                page=page,
                per_page=per_page,
                search=search,
                year=year,
                semester=semester,
                college=college
            )

            return jsonify({
                'success': True,
                'data': result['data'],
                'total': result['total'],
                'page': page,
                'per_page': per_page,
                'pages': result['pages'],
                'has_prev': result['has_prev'],
                'has_next': result['has_next']
            })
    except Exception as e:
        logger.error(f"获取班级列表失败: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500

@app.route('/api/teachers')
def api_teachers():
    """获取教师列表API（支持条件查询和分页）"""
    try:
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 20, type=int)  # 每页默认20条
        search = request.args.get('search', '', type=str)  # 搜索关键词
        department = request.args.get('department', '', type=str)  # 部门筛选
        semester = request.args.get('semester', '', type=str)  # 学期筛选

        # 限制每页最大数量
        per_page = min(per_page, 100)

        with app.app_context():
            result = ScheduleManager.get_teacher_list_paginated(
                page=page,
                per_page=per_page,
                search=search,
                department=department,
                semester=semester
            )

            return jsonify({
                'success': True,
                'data': result['data'],
                'total': result['total'],
                'page': page,
                'per_page': per_page,
                'pages': result['pages'],
                'has_prev': result['has_prev'],
                'has_next': result['has_next']
            })
    except Exception as e:
        logger.error(f"获取教师列表失败: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500

@app.route('/api/schedule/<class_id>')
def api_schedule(class_id):
    """获取指定班级的课程表API"""
    try:
        with app.app_context():
            schedules = ScheduleManager.get_class_schedule(class_id)

            if not schedules:
                return jsonify({'error': '班级不存在或无课程数据'}), 404

            # 获取班级信息
            class_info = schedules[0]

            # 转换为旧格式以兼容现有的解析器
            class_data = {
                'class_id': class_info.class_id,
                'class_name': class_info.class_name,
                'semester': class_info.semester,
                'schedules': [schedule.raw_data for schedule in schedules if schedule.raw_data]
            }

            # 解析课程表数据
            courses = parser.parse_schedule_data(class_data)
            schedule_table = parser.generate_schedule_table(courses)

            # 准备返回数据
            result = {
                'class_info': {
                    'class_id': class_info.class_id,
                    'class_name': class_info.class_name,
                    'semester': class_info.semester,
                    'total_courses': len(courses)
                },
                'time_slots': parser.time_slots,
                'weekdays': parser.weekdays,
                'courses': courses,
                'schedule_table': schedule_table
            }

            return jsonify(result)
    except Exception as e:
        logger.error(f"获取班级课程表失败: {e}")
        return jsonify({'error': str(e)}), 500

@app.route('/api/teacher_schedule/<teacher_id>')
def api_teacher_schedule(teacher_id):
    """获取指定教师的课程表API"""
    try:
        with app.app_context():
            schedules = ScheduleManager.get_teacher_schedule(teacher_id)

            if not schedules:
                return jsonify({'error': '教师不存在或无课程数据'}), 404

            # 获取教师信息
            teacher_info = schedules[0]

            # 转换为旧格式以兼容现有的解析器
            teacher_data_item = {
                'teacher_id': teacher_info.teacher_id,
                'teacher_name': teacher_info.teacher_name,
                'department': teacher_info.department,
                'teacher_title': teacher_info.teacher_title,
                'semester': teacher_info.semester,
                'schedules': [schedule.raw_data for schedule in schedules if schedule.raw_data]
            }

            # 解析课程表数据
            courses = parser.parse_schedule_data(teacher_data_item)
            schedule_table = parser.generate_schedule_table(courses)

            # 准备返回数据
            result = {
                'teacher_info': {
                    'teacher_id': teacher_info.teacher_id,
                    'teacher_name': teacher_info.teacher_name,
                    'department': teacher_info.department,
                    'teacher_title': teacher_info.teacher_title,
                    'semester': teacher_info.semester,
                    'total_courses': len(courses)
                },
                'time_slots': parser.time_slots,
                'weekdays': parser.weekdays,
                'courses': courses,
                'schedule_table': schedule_table
            }

            return jsonify(result)
    except Exception as e:
        logger.error(f"获取教师课程表失败: {e}")
        return jsonify({'error': str(e)}), 500

@app.route('/class/<class_id>')
def class_schedule(class_id):
    """班级课程表页面"""
    return render_template('schedule.html', class_id=class_id, type='class')

@app.route('/teacher/<teacher_id>')
def teacher_schedule(teacher_id):
    """教师课程表页面"""
    return render_template('schedule.html', class_id=teacher_id, type='teacher')

@app.route('/api/scrape/status')
def api_scrape_status():
    """获取采集状态API"""
    return jsonify(scraping_status)

@app.route('/api/scrape/class', methods=['POST'])
def api_scrape_class():
    """开始采集班级课程表API"""
    global scraping_status
    
    if scraping_status['class_scraping']:
        return jsonify({'error': '班级课程表正在采集中，请稍候'}), 400
    
    # 获取参数
    data = request.get_json()
    cookies = data.get('cookies', '')
    year = data.get('year', '')  # 空字符串表示不限制年级
    college_code = data.get('college_code', '')  # 空字符串表示不限制学院
    major_code = data.get('major_code', '')  # 空字符串表示不限制专业
    semester = data.get('semester', '2025-2026-1')  # 默认学期
    
    if not cookies:
        return jsonify({'error': '请提供有效的cookies'}), 400
    
    # 设置cookies
    set_cookies(cookies)
    
    # 启动采集线程
    def scrape_class_thread():
        global scraping_status
        scraping_status['class_scraping'] = True
        scraping_status['class_progress'] = 0
        # 构建采集范围描述
        scope_parts = []
        if year:
            scope_parts.append(f'年级:{year}')
        if college_code:
            scope_parts.append(f'院系:{college_code}')
        if major_code:
            scope_parts.append(f'专业:{major_code}')

        scope_desc = ', '.join(scope_parts) if scope_parts else '全校所有'
        scraping_status['class_message'] = f'开始采集班级课程表... ({scope_desc})'
        
        try:
            success = scrape_classes(year, college_code, major_code, semester, app_context=app.app_context())
            if success:
                scraping_status['class_message'] = '班级课程表采集完成，数据已保存到数据库'
            else:
                scraping_status['class_message'] = '采集失败，请检查cookies是否有效'
        except Exception as e:
            scraping_status['class_message'] = f'采集出错: {str(e)}'
        finally:
            scraping_status['class_scraping'] = False
            scraping_status['class_progress'] = 100
    
    thread = threading.Thread(target=scrape_class_thread)
    thread.daemon = True
    thread.start()
    
    return jsonify({'message': '班级课程表采集已开始'})

@app.route('/api/scrape/teacher', methods=['POST'])
def api_scrape_teacher():
    """开始采集教师课程表API"""
    global scraping_status
    
    if scraping_status['teacher_scraping']:
        return jsonify({'error': '教师课程表正在采集中，请稍候'}), 400
    
    # 获取参数
    data = request.get_json()
    cookies = data.get('cookies', '')
    teacher_name = data.get('teacher_name', '')
    teacher_id = data.get('teacher_id', '')
    semester = data.get('semester', '2025-2026-1')  # 默认学期
    
    if not cookies:
        return jsonify({'error': '请提供有效的cookies'}), 400
    
    # 设置cookies
    set_cookies(cookies)
    
    # 启动采集线程
    def scrape_teacher_thread():
        global scraping_status
        scraping_status['teacher_scraping'] = True
        scraping_status['teacher_progress'] = 0
        
        # 构建状态消息
        if teacher_name:
            scraping_status['teacher_message'] = f'开始采集教师课程表... (姓名: {teacher_name})'
        elif teacher_id:
            scraping_status['teacher_message'] = f'开始采集教师课程表... (工号: {teacher_id})'
        else:
            scraping_status['teacher_message'] = '开始采集教师课程表... (所有教师)'
        
        try:
            success = scrape_teachers(teacher_name=teacher_name, teacher_id=teacher_id, semester=semester, app_context=app.app_context())
            if success:
                scraping_status['teacher_message'] = '教师课程表采集完成，数据已保存到数据库'
            else:
                scraping_status['teacher_message'] = '采集失败，请检查cookies是否有效或教师信息是否正确'
        except Exception as e:
            scraping_status['teacher_message'] = f'采集出错: {str(e)}'
        finally:
            scraping_status['teacher_scraping'] = False
            scraping_status['teacher_progress'] = 100
    
    thread = threading.Thread(target=scrape_teacher_thread)
    thread.daemon = True
    thread.start()
    
    return jsonify({'message': '教师课程表采集已开始'})

if __name__ == '__main__':
    try:
        logger.info("="*50)
        logger.info("滇西科技师范学院课程表管理系统")
        logger.info("="*50)

        with app.app_context():
            # 创建表（如果不存在）
            db.create_all()

            # 获取统计信息
            stats = get_database_stats()
            logger.info(f"数据库统计: {stats['classes_count']} 个班级, {stats['teachers_count']} 个教师")
            logger.info(f"课程记录: 班级课表 {stats['class_schedules_count']} 条, 教师课表 {stats['teacher_schedules_count']} 条")

        logger.info("本地访问地址: http://127.0.0.1:5000")
        logger.info("远程访问地址: http://0.0.0.0:5000")
        logger.info("="*50)

        app.run(debug=True, host='0.0.0.0', port=5000)

    except Exception as e:
        logger.error(f"启动失败: {e}")
        import traceback
        traceback.print_exc()
        input("按回车键退出...")
